namespace SimpleWebServices.Web.UI.Html.Elements
{
    using System;
    using System.Xml.Serialization;
    using SimpleWebServices;
    using Xunit;

    /// TODO: add more properties, see http://www.w3.org/TR/html401/struct/links.html#edef-LINK
    public sealed class LinkFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Link>()
                .DerivesFrom<Element>()
                .IsConcreteClass()
                .IsUnsealed()
                .HasDefaultConstructor()
                .Implements<IXmlSerializable>()
                .XmlRoot("link")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            Link expected = new Link
            {
                Id = "id",
                Class = "class",
                Language = "fr",
                Hyperlink = new Uri("http://example.com/target"),
                Relationship = "relationship",
                ReverseLink = "reverse",
                Title = "title",
                Type = "text/plain"
            };

            string xml = "<link id='id' class='class' lang='fr' title='title' href='http://example.com/target' rel='relationship' rev='reverse' type='text/plain' />";
            Link actual = xml.Deserialize<Link>();

            Assert.Equal<string>(expected.ToString(), actual.ToString());
        }

        [Fact]
        public void deserializeEmpty()
        {
            Assert.NotNull("<link />".Deserialize<Link>());
        }

        [Fact]
        public void serialize()
        {
            Link obj = new Link
            {
                Id = "id",
                Class = "class",
                Language = "fr",
                Hyperlink = new Uri("http://example.com/target"),
                Relationship = "relationship",
                ReverseLink = "reverse",
                Title = "title",
                Type = "text/plain"
            };

            string xpath = "1=count(/link[@id='id'][@class='class'][@lang='fr'][@title='title'][@href='http://example.com/target'][@rel='relationship'][@rev='reverse'][@type='text/plain'])";
            
            Assert.True((bool)obj.Serialize().CreateNavigator().Evaluate(xpath));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Link());
        }

        [Fact]
        public void prop_Hyperlink()
        {
            Assert.True(new PropertyExpectations(typeof(Link).GetProperty("Hyperlink"))
                .IsAutoProperty<Uri>()
                .Result);
        }

        [Fact]
        public void prop_Relationship()
        {
            Assert.True(new PropertyExpectations(typeof(Link).GetProperty("Relationship"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_ReverseLink()
        {
            Assert.True(new PropertyExpectations(typeof(Link).GetProperty("ReverseLink"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Type()
        {
            Assert.True(new PropertyExpectations(typeof(Link).GetProperty("Type"))
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void opEquality_Link_Link()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_Link_LinkDiffers()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = new Link
            {
                Relationship = "next",
                Hyperlink = new Uri("http://example.com/next")
            };

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Link_LinkSame()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = obj;

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_LinkNull_Link()
        {
            Link obj = null;

            Link comparand = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Link_LinkNull()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = null;

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opInequality_Link_Link()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_Link_LinkDiffers()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = new Link
            {
                Relationship = "next",
                Hyperlink = new Uri("http://example.com/next")
            };

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Link_LinkSame()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = obj;

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_LinkNull_Link()
        {
            Link obj = null;

            Link comparand = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Link_LinkNull()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = null;

            Assert.True(obj != comparand);
        }

        [Fact]
        public void op_Deserialize_string_string_string()
        {
            Link expected = new Link
            {
                Id = "id",
                Class = "class",
                Language = "fr",
                Hyperlink = new Uri("http://example.com/target"),
                Relationship = "relationship",
                ReverseLink = "reverse",
                Title = "title"
            };

            string xml = "<link id='id' class='class' lang='fr' title='title' href='http://example.com/target' rel='relationship' rev='reverse' />";
            Link actual = new Link().Deserialize("link", null, xml) as Link;

            Assert.Equal<Link>(expected, actual);
        }

        [Fact]
        public void op_GetHashCode()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            int expected = obj.ToString().GetHashCode();
            int actual = obj.GetHashCode();

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_Equals_object()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Assert.True(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectDiffer()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Link comparand = new Link
            {
                Relationship = "next",
                Hyperlink = new Uri("http://example.com/next")
            };

            Assert.False(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectSame()
        {
            Link obj = new Link
            {
                Relationship = "prev",
                Hyperlink = new Uri("http://example.com/link")
            };

            Assert.True(obj.Equals(obj as object));
        }

        [Fact]
        public void op_Equals_objectNull()
        {
            Assert.False(new Link().Equals(null as object));
        }

        [Fact]
        public void op_Equals_objectString()
        {
            Assert.False(new Link().Equals(string.Empty));
        }
    }
}